package etc.server.etc;


import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Objects;

/**
 * @author lee
 */
@Slf4j
@Data
@AllArgsConstructor
public class EtcPack {

    private final static String encoding = "GBK";
    private String ip;
    private int port;


    public static byte[] dynamickey = new byte[24];

    private static final byte[] keybytes = {0x01, 0x01, 0x02, 0x02, 0x03,
            0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01,
            0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04};



    public static byte[] headSet(String reqbody, String reqtype, int bodyconlen, int id) {
        String verifyCode = SecureUtil.md5(reqbody);
        MsgHeader phr = new MsgHeader();
        phr.setMessageId(StrUtil.padPre(String.valueOf(id), 4, "0"));
        int totalLen = 58 + bodyconlen;
        phr.setMessageLength(StrUtil.padPre(String.valueOf(totalLen), 4, "0"));
        phr.setMessageType(reqtype);
        phr.setReceiverId("1400000");
        phr.setSenderId("8000001");
        phr.setVerifyCode(verifyCode.toUpperCase());
        //System.out.println("MessageLength：" + phr.getMessageLength());
        System.out.println("client--" + phr.getMessageType() + "---header:" + phr.toString());
        byte[] head = new byte[58];
        byte[] head1 = Convert.int2Bytes(totalLen);
        byte[] head2 = (phr.getReceiverId() + phr.getSenderId() + phr
                .getMessageType()).getBytes();
        byte[] head3 = Convert.int2Bytes(id);
        byte[] head4 = phr.getVerifyCode().getBytes();
        System.arraycopy(head1, 0, head, 0, head1.length);
        System.arraycopy(head2, 0, head, head1.length, head2.length);
        System.arraycopy(head3, 0, head, head1.length + head2.length,
                head3.length);
        System.arraycopy(head4, 0, head, head1.length + head2.length
                + head3.length, head4.length);
        return head;
    }

    public static byte[] packSet(String reqbody, String reqType, int id)
            throws Exception {

        int bodyconlen = Math.round((reqbody.length() >> 3) + 1) << 3;
        if (bodyconlen > reqbody.length()) {
            reqbody = StrUtil.padAfter(reqbody, bodyconlen, " ");
        }
        byte[] encBodyBytes;

        if (Objects.equals(reqType, "1001")) {
            encBodyBytes = CryptoUtil.encrypt(reqbody, keybytes);
        } else {
            encBodyBytes = CryptoUtil.encrypt(reqbody, dynamickey);
        }

        byte[] reqHead = headSet(reqbody, reqType, bodyconlen, id);
        byte[] message = new byte[reqHead.length + encBodyBytes.length];
        System.arraycopy(reqHead, 0, message, 0, reqHead.length);
        System.arraycopy(encBodyBytes, 0, message, reqHead.length, encBodyBytes.length);
        return message;
    }


    public String send1001(String msg) throws Exception {
        StringBuilder responseBody = new StringBuilder(DateTools.getDateTimeString());
        log.info("client--1001--req--body:{}", responseBody.toString());
        try {
            byte[] reqMsg = packSet(responseBody.toString(), "1001", 1);
            log.info("1001--req--data:{}", reqMsg);
            byte[] response = EtcClient.socket(reqMsg, ip, port);
            MsgHeader ph = new MsgHeader();
            //System.out.println("client--1001--res：" + new String(response));
            byte[] resHead = new byte[58];
            System.arraycopy(response, 0, resHead, 0, 58);
            ph.analyze(resHead);
            log.info("client--1002--res--header:{}", ph.toString());
            byte[] resbody = new byte[response.length - 58];
            System.arraycopy(response, 58, resbody, 0, response.length - 58);
            byte[] decbodybyte;
            decbodybyte = CryptoUtil.decrypt(resbody, keybytes);

            String decBody = new String(decbodybyte, encoding);
            log.info("client--1002--res--body--dec:{}", decBody);
            String key = decBody.substring(16);
            dynamickey = CryptoUtil.getKey(key.getBytes());
            log.info("client--1002--dynamickey--keybytes:{}", Arrays.toString(dynamickey));

            return send1003(3, msg);

        } catch (Exception e) {
            log.error("报文1001发送异常！", e);
            throw new Exception(e);
        } finally {
            EtcClient.close();
        }
    }

    public String send1003(int id, String msg) {
        StringBuilder sb = new StringBuilder();
        String dts = DateTools.getDateTimeString();
        sb.append(dts);
        sb.append("8000123");
        sb.append("8000123001");
        log.info("client--1003--req--body:{}", sb.toString());
        try {
            byte[] reqMsg = packSet(sb.toString(), "1003", id);
            byte[] resBody = sendBody(reqMsg, ip, port);
            log.info("client--1003--res--body--dec:{}", new String(resBody, encoding));

            if ("4001".equals(msg)) {
                return send4001(id + 2);
            } else {
                return send(id + 2, msg);
            }
        } catch (Exception e) {
            log.error("报文1003发送异常！", e);
            throw new RuntimeException(e);
        }
    }

    public String send(int n, String msg) throws Exception {
        String reqbody = msg.substring(18);
        log.info("client--receive--body:{}", reqbody);
        log.info("client--receive--body--length:{}", reqbody.length());
        String reqHead = msg.substring(0, 18);
        String verifyCode = SecureUtil.md5(reqbody);
        MsgHeader mh = new MsgHeader();
        mh.setMessageId(StrUtil.padPre(String.valueOf(n), 4, "0"));
        int bodyLen = Math.round((reqbody.length() >> 3) + 1) << 3;
        if (bodyLen > reqbody.length()) {
            reqbody = StrUtil.padAfter(reqbody, bodyLen, " ");
        }
        int totalLen = 58 + bodyLen;
        mh.setMessageLength(StrUtil.padPre(String.valueOf(totalLen), 4, "0"));
        mh.setMessageType(reqHead.substring(14, 18));
        mh.setReceiverId(reqHead.substring(0, 7));
        mh.setSenderId(reqHead.substring(7, 14));
        mh.setVerifyCode(verifyCode.toUpperCase());
        //System.out.println("MessageLength：" + phr.getMessageLength());
        log.info("client--{}---header:{}", mh.getMessageType(), mh.toString());
        log.info("client--{}---header--length:{}", mh.getMessageType(), mh.toString().length());
        log.info("client--{}---message:{}", mh.getMessageType(), mh.toString() + reqbody);
        log.info("client--{}---length:{}", mh.getMessageType(), (mh.toString() + reqbody).length());
        byte[] head = mh.headSet(reqbody);
        byte[] encBodyBytes;
        encBodyBytes = CryptoUtil.encrypt(reqbody, dynamickey);

        byte[] message = new byte[head.length + encBodyBytes.length];
        System.arraycopy(head, 0, message, 0, head.length);
        System.arraycopy(encBodyBytes, 0, message, head.length, encBodyBytes.length);
        log.info("client--{}--message--length:{}", mh.getMessageType(), message.length);
        byte[] res = EtcClient.socket(message, ip, port);
        log.info("client--receive:{}", res);
        if (res != null && res.length > 0) {
            byte[] resHead = new byte[58];
            System.arraycopy(res, 0, resHead, 0, 58);
            byte[] resBody = new byte[res.length - 58];
            System.arraycopy(res, 58, resBody, 0, res.length - 58);
            MsgHeader rmh = new MsgHeader();
            rmh.analyze(resHead);
            byte[] decBodyByte;
            decBodyByte = CryptoUtil.decrypt(resBody, dynamickey);
            String decBody = new String(decBodyByte, encoding);
            log.info("client--{}--dec:{}", mh.getMessageType(), decBody);
            return rmh.toString() + decBody;
        }
        return null;

    }

    public String send4001(int id) {
        try {
            Request4001 req = new Request4001();
            req.setProcessDate(DateTools.getDateStr());
            req.setProcessTime(DateTools.getTimeStr());
            req.setNetWorkID("4000123");
            req.setTerminalID("4000123001");
            req.setBackId("3300000");
            req.setCustomerID(StrUtil.padAfter("1847378", 20, " "));

            req.setUserName(StrUtil.padAfter("孙燕姿", 100, " "));
            req.setUserType("05");
            req.setCertificateType("01");
            req.setCertificateId(StrUtil.padAfter("141125199208080157", 60, " "));
            req.setPCardNetId("1401");
            req.setPCardId("14011111111111");
            req.setEntrustVerifyCode(RandomUtil.randomString(16));
            req.setVehplate(StrUtil.padAfter("晋J1350", 12, " "));
            req.setVehplateColor("00");
            req.setVehType("01");
            req.setVehSeatNum("06");
            req.setWasteSN(req.getTerminalID() + req.getProcessDate() + req.getProcessTime() + "003");
            req.setBankCardType("01");
            req.setBCertificateType("00");
            req.setBVCertificateID(StrUtil.padAfter(RandomUtil.randomNumbers(16), 60, " "));
            req.setActiveDate("202211");
            req.setBankCardID(StrUtil.padAfter(RandomUtil.randomNumbers(19), 32, " "));
            req.setBUserName(StrUtil.padAfter("孙燕姿", 20, " "));
            req.setOperatorName(StrUtil.padAfter("郁可唯", 20, " "));
            req.setBankCustomerID(RandomUtil.randomNumbers(12));
            req.setRemark(StrUtil.padAfter("无备注", 50, " "));


            System.out.println("4001报文体:" + req.toString());

            byte[] reqcontent = packSet(req.toString(), "4001", id);
            System.out.println("reqcontent长度：" + reqcontent.length);
            String reqstr = new String(reqcontent, encoding);
            System.out.println("reqcontent：" + reqstr);
            byte[] decbodybyte = sendBody(reqcontent, ip, port);
            String byte2Str = new String(decbodybyte, encoding);
            System.out.println("解密后的应答报体内容：" + byte2Str);
            return byte2Str;
        } catch (Exception e) {
            log.error("报文4001发送异常！");
            e.printStackTrace();
        }
        return null;
    }


    private byte[] sendBody(byte[] reqMsg, String ip, int port)
            throws Exception {
        byte[] response = EtcClient.socket(reqMsg, ip, port);
        MsgHeader ph = new MsgHeader();
        byte[] resHead = new byte[58];
        System.arraycopy(response, 0, resHead, 0, 58);
        ph.analyze(resHead);
        byte[] resbody = new byte[response.length - 58];
        System.arraycopy(response, 58, resbody, 0, response.length - 58);
        return CryptoUtil.decrypt(resbody, dynamickey);

    }
}
